#include <GameEngine/Graphics/Meshes/mesh_renderer.h>

#include <GameEngine/Graphics/Meshes/surface_mesh.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Constructor
MeshRenderer::MeshRenderer(SurfaceMesh* mesh) : mesh_(mesh), SceneElement() {}

//! Copy constructor
/*!
 @param rhs The mesh renderer to copy
 */
MeshRenderer::MeshRenderer(const MeshRenderer& rhs) : mesh_(rhs.mesh_),
	list_(rhs.list_), transformer_(rhs.transformer_), SceneElement(rhs) {}

//! Assignment operator
/*!
 @param rhs The mesh renderer to copy
 @return A reference to this transformed element
 */
MeshRenderer& MeshRenderer::operator=(const MeshRenderer& rhs) {
	if ( &rhs != this ) {
		mesh_ = rhs.mesh_;
		list_ = rhs.list_;
		transformer_ = rhs.transformer_;
		SceneElement::operator=(rhs);
	}
	return *this;
}

//! Destructor
MeshRenderer::~MeshRenderer() {}

//! Accessor to the 3D transformer of the mesh (read-write)
/*!
 @return A reference to the 3D transformer of the mesh
 */
GLTransformer3d& MeshRenderer::transformer() {
	return transformer_;
}

//! Accessor to the 3D transformer of the mesh (read only)
/*!
 @return A constant reference to the 3D transformer of the mesh
 */
const GLTransformer3d& MeshRenderer::transformer() const {
	return transformer_;
}

//! Change the mesh associated to the mesh renderer
/*!
 @param mesh The new mesh to render (may be nil for no new mesh)
 */
void MeshRenderer::set_mesh(SurfaceMesh* mesh) {
	mesh_ = mesh;
	list_.clear();
}

//! Check if the mesh renderer is valid
/*!
 @return True if the renderer is ready to draw a mesh, false otherwise
 */
bool MeshRenderer::valid() const {
	return ( mesh_ != nil );
}

//! Draw the mesh associated to the renderer
/*!
 @param ray The picking ray under the mouse
 @return True if the mesh could be drawn, false otherwise
 */
bool MeshRenderer::draw(const Line3d<float>& ray) {
	// Check the renderer
	if ( valid() == false ) return false;

	// If display list is not yet generated, generate it
	bool res = true;
	if ( list_.initialized() == false ) {
		list_.begin_display_list();
		res &= mesh_->render_mesh(ray,false);
		list_.end_display_list();
	}

	// Render the mesh
	transformer_.apply_transformation();

	// Opaque geometry
	list_.draw();

	// Transparent geometry
	glEnable( GL_BLEND );
	glDepthMask( GL_FALSE );
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
	res &= mesh_->render_mesh(ray,true);
	glDisable( GL_BLEND );
	glDepthMask( GL_TRUE );

	transformer_.remove_transformation();
	return res;
}


#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif
